#include <stdio.h>
#include <string.h>
#include "bsp_i2c.h"
#include <gd32f10x_i2c.h> // GigaDevice::Device:GD32F10x_StdPeripherals:I2C
#include <gd32f10x_rcu.h> // GigaDevice::Device:GD32F10x_StdPeripherals:RCU

#include "systick.h"
// #include "MsgQueue.h"

#define BUF_MAX_LEN (256)

/* 从机的接收和发送缓冲 */
uint8_t Buffer_Rx_IIC[BUF_MAX_LEN]; // 接收缓存
uint8_t Rx_Idx_IIC = 0;             // 接收计数
uint8_t Flag_RcvOK_IIC = 0;         // 接收完成标志

void resetI2cMaster(uint32_t I2Cx);

/**
 * @brief I2C GPIO初始化
 * @param 无
 * @retval 无
 */
static void MASTER_I2C_GPIO_Config(uint32_t i2cx)
{

    switch (i2cx)
    {
    case 0:
        /* 使能与 I2C 有关的时钟 */
        MASTER_I2C1_APBxClock_FUN(MASTER_I2C1_CLK);
        MASTER_I2C1_GPIO_APBxClock_FUN(MASTER_I2C1_GPIO_CLK);

        /* I2C_SCL */
        gpio_init(MASTER_I2C1_SCL_PORT, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, MASTER_I2C1_SCL_PIN);

        /* I2C_SDA*/
        gpio_init(MASTER_I2C1_SDA_PORT, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, MASTER_I2C1_SDA_PIN);
        break;
    case 1:
        /* 使能与 I2C 有关的时钟 */
        MASTER_I2C2_APBxClock_FUN(MASTER_I2C2_CLK);
        MASTER_I2C2_GPIO_APBxClock_FUN(MASTER_I2C2_GPIO_CLK);

        /* I2C_SCL */
        gpio_init(MASTER_I2C2_SCL_PORT, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, MASTER_I2C2_SCL_PIN);

        /* I2C_SDA*/
        gpio_init(MASTER_I2C2_SDA_PORT, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, MASTER_I2C2_SDA_PIN);
        break;
    default:
        break;
    }
}

/**
 * @brief I2C 模式初始化
 * @param 无
 * @retval 无
 */
static void MASTER_I2C_Mode_Configu(uint32_t i2cx)
{

    switch (i2cx)
    {
    case 0:
        /* 高电平数据稳定，低电平数据变化 SCL 时钟线的占空比 */
        /* 通信速率 100kHz*/
        i2c_clock_config(MASTER_I2C1, I2C_Speed, I2C_DTCY_2);
        /* I2C 的寻址模式 */
        i2c_mode_addr_config(MASTER_I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0);
        i2c_ack_config(MASTER_I2C1, I2C_ACK_DISABLE);
        /* 使能 I2C */
        i2c_enable(MASTER_I2C1);
        break;
    case 1:
        /* 高电平数据稳定，低电平数据变化 SCL 时钟线的占空比 */
        /* 通信速率 100kHz*/
        i2c_clock_config(MASTER_I2C2, I2C_Speed, I2C_DTCY_2);
        /* I2C 的寻址模式 */
        i2c_mode_addr_config(MASTER_I2C2, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0);
        i2c_ack_config(MASTER_I2C2, I2C_ACK_DISABLE);
        /* 使能 I2C */
        i2c_enable(MASTER_I2C2);
        break;
    default:
        break;
    }
}

/**
 * @brief I2C模块初始化
 * @param 无
 * @retval 无
 */
void MASTER_I2C_Init(void)
{
    MASTER_I2C_GPIO_Config(0);
    MASTER_I2C_Mode_Configu(0);
    MASTER_I2C_GPIO_Config(1);
    MASTER_I2C_Mode_Configu(1);
}

/**
* @brief I2C主机发送
* @param 	I2Cx：I2C1或I2C2 发送IIC
  @param    pBuffer：待发送数据
  @param    NumByteToWrite：待发送数据长度
  @param    SlaveAddress：从机地址即目标地址
* @retval 无
*/
uint8_t I2C_Master_BufferWrite(uint32_t I2Cx, uint8_t *pBuffer, uint32_t NumByteToWrite, uint8_t SlaveAddress)
{
    unsigned int timeout = 0;
    static unsigned int busyCnt = 0; /* 总线忙计数器 超过3次则强制发送起始信号 */
    //uint32_t stat0 = 0;

    if (NumByteToWrite == 0)
        return 1;

    /* 0.等待总线空闲*/
    timeout = I2CT_LONG_TIMEOUT;
    while (i2c_flag_get(I2Cx, I2C_FLAG_I2CBSY))
    {
        if ((timeout--) == 0)
        {
            if (++busyCnt >= 3)
            {
                break;
            }

            printf("I2C send timeout:[I2C_BUSY]\r\n");
            return 1;
        }
    }

    busyCnt = 0;
    i2c_ack_config(I2Cx, I2C_ACK_ENABLE);

    /* 1.开始*/
    timeout = I2CT_FLAG_TIMEOUT;
    i2c_start_on_bus(I2Cx);
    while (!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND))
    {
        if ((timeout--) == 0)
        {
            printf("I2C send timeout:[I2C_FLAG_SBSEND]\r\n");
            return 1;
        }
    }

    /* 2.设备地址·写 */
    timeout = I2CT_LONG_TIMEOUT;
    i2c_master_addressing(I2Cx, SlaveAddress, I2C_TRANSMITTER);

    while (SET != i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND))
    {
        if ((timeout--) == 0)
        {
            printf("I2C send timeout:[I2C_FLAG_ADDSEND]\r\n");
            i2c_stop_on_bus(I2Cx); /* 发出终止信号，释放总线 */
            resetI2cMaster(I2Cx);
            return 1;
        }
    }

    i2c_flag_clear(I2Cx, I2C_FLAG_ADDSEND);
    timeout = I2CT_LONG_TIMEOUT;
    while (!i2c_flag_get(I2Cx, I2C_FLAG_TBE))
    {
        if ((timeout--) == 0)
        {
            printf("I2C send timeout:[I2C_FLAG_TBE]\r\n");
            i2c_stop_on_bus(I2Cx); /* 发出终止信号，释放总线 */
            return 1;
        }
    }

    /* 3.连续写数据 */
    while (NumByteToWrite--)
    {
        timeout = I2CT_LONG_TIMEOUT;
        i2c_data_transmit(I2Cx, *pBuffer);
        while (!i2c_flag_get(I2Cx, I2C_FLAG_BTC))
        {
#if 1
            if ((timeout--) == 0)
            {
                printf("I2C send timeout:[I2C_FLAG_BTC]\r\n");
                i2c_stop_on_bus(I2Cx); /* 发出终止信号，释放总线 */
                          resetI2cMaster(I2Cx);  
							return 1;
            }
#endif
        }
        pBuffer++;
    }
    /* 4.停止 */
    i2c_stop_on_bus(I2Cx);

    while ((I2C_CTL0(I2Cx) & 0x200) == 0x200)
        ;

    return 0;
}

/**
* @brief I2C主机接收
* @description 先发送一个需要读的地址，紧接着重新发送开始信号，开始读数据
* @param 	I2Cx：I2C1或I2C2 主机IIC
            pBuffer：接收数据缓冲
            NumByteToRead：欲接收数据长度
            SlaveAddress：从机地址即目标地址
* @retval 无
*/
uint8_t I2C_Master_BufferRead(uint32_t I2Cx, uint8_t *pBuffer, uint32_t NumByteToRead, uint8_t SlaveAddress)
{
    static unsigned int busyCnt = 0; /* 总线忙计数器 超过3次则强制发送起始信号 */
    unsigned int timeout = 0;
    //uint32_t stat0 = 0;

    if (NumByteToRead == 0)
        return 1;
    /* 0.等待总线空闲*/
    /* wait until I2C bus is idle */
    timeout = I2CT_LONG_TIMEOUT;
    while (i2c_flag_get(I2Cx, I2C_FLAG_I2CBSY))
    {
        if ((timeout--) == 0)
        {
            if (++busyCnt >= 3)
            {
                break;
            }

            printf("I2C recv timeout:[I2C_FLAG_I2CBSY]\r\n");
            return 1;
        }
    }

    if (2 == NumByteToRead)
    {
        i2c_ackpos_config(I2Cx, I2C_ACKPOS_NEXT);
    }

    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2Cx);
    timeout = I2CT_FLAG_TIMEOUT;
    /* wait until SBSEND bit is set */
    while (!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND))
    {
        if ((timeout--) == 0)
        {
            printf("I2C recv timeout:[I2C_FLAG_SBSEND]\r\n");
            return 1;
        }
    }

    /* send slave address to I2C bus */
    i2c_master_addressing(I2Cx, SlaveAddress, I2C_TRANSMITTER);
    timeout = I2CT_LONG_TIMEOUT;

    /* wait until ADDSEND bit is set */
    while (!i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND))
    {
        if ((timeout--) == 0)
        {
            printf("I2C recv timeout:[I2C_FLAG_ADDSEND] write\r\n");
            i2c_stop_on_bus(I2Cx); /* 发出终止信号，释放总线 */
            resetI2cMaster(I2Cx);
            return 1;
        }
    }

    /* clear the ADDSEND bit */
    i2c_flag_clear(I2Cx, I2C_FLAG_ADDSEND);
    timeout = I2CT_LONG_TIMEOUT;
    /* wait until the transmit data buffer is empty */
    while (SET != i2c_flag_get(I2Cx, I2C_FLAG_TBE))
    {
        if ((timeout--) == 0)
        {
            printf("I2C recv timeout:[I2C_FLAG_TBE]\r\n");
            i2c_stop_on_bus(I2Cx); /* 发出终止信号，释放总线 */
            return 1;
        }
    }

    /* enable I2Cx*/
    i2c_enable(I2Cx);

    /* send the EEPROM's internal address to write to */
    i2c_data_transmit(I2Cx, *pBuffer);
    timeout = I2CT_LONG_TIMEOUT;

    /* wait until BTC bit is set */
    while (!i2c_flag_get(I2Cx, I2C_FLAG_BTC))
    {
        if ((timeout--) == 0)
        {
            printf("I2C On Recv be send reg timeout:[I2C_FLAG_BTC]\r\n");
            i2c_stop_on_bus(I2Cx); /* 发出终止信号，释放总线 */
            return 1;
        }
    }

    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2Cx);
    timeout = I2CT_FLAG_TIMEOUT;
    /* wait until SBSEND bit is set */
    while (!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND))
    {
        if ((timeout--) == 0)
        {
            printf("I2C recv timeout:[I2C_FLAG_SBSEND] next\r\n");
            return 1;
        }
    }

    /* send slave address to I2C bus */
    i2c_master_addressing(I2Cx, SlaveAddress, I2C_RECEIVER);

    if (NumByteToRead < 3)
    {
        /* disable acknowledge */
        i2c_ack_config(I2Cx, I2C_ACK_DISABLE);
    }
    timeout = I2CT_LONG_TIMEOUT;
    /* wait until ADDSEND bit is set */
    while (!i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND))
    {
        if ((timeout--) == 0)
        {
            printf("I2C recv timeout:[I2C_FLAG_ADDSEND] Read\r\n");
            i2c_stop_on_bus(I2Cx); /* 发出终止信号，释放总线 */
            resetI2cMaster(I2Cx);
            return 1;
        }
    }

    /* clear the ADDSEND bit */
    i2c_flag_clear(I2Cx, I2C_FLAG_ADDSEND);

    if (1 == NumByteToRead)
    {
        /* send a stop condition to I2C bus */
        i2c_stop_on_bus(I2Cx);
    }

    /* while there is data to be read */
    while (NumByteToRead)
    {
        if (3 == NumByteToRead)
        {
            timeout = I2CT_LONG_TIMEOUT;
            /* wait until BTC bit is set */
            while (!i2c_flag_get(I2Cx, I2C_FLAG_BTC))
            {
                if ((timeout--) == 0)
                {
                    printf("I2C recv timeout:[I2C_FLAG_BTC]\r\n");
                    return 1;
                }
            }

            /* disable acknowledge */
            i2c_ack_config(I2Cx, I2C_ACK_DISABLE);
        }
        if (2 == NumByteToRead)
        {
            /* wait until BTC bit is set */
            while (!i2c_flag_get(I2Cx, I2C_FLAG_BTC))
            {
                if ((timeout--) == 0)
                {
                    printf("I2C recv timeout:[I2C_FLAG_BTC]\r\n");
                    return 1;
                }
            }

            /* send a stop condition to I2C bus */
            i2c_stop_on_bus(I2Cx);
        }

        /* wait until the RBNE bit is set and clear it */
        if (i2c_flag_get(I2Cx, I2C_FLAG_RBNE))
        {
            /* read a byte from the EEPROM */
            *pBuffer = i2c_data_receive(I2Cx);

            /* point to the next location where the byte read will be saved */
            pBuffer++;

            /* decrement the read bytes counter */
            NumByteToRead--;
        }
    }

    /* wait until the stop condition is finished */
    while (I2C_CTL0(I2Cx) & 0x0200)
        ;

    /* enable acknowledge */
    i2c_ack_config(I2Cx, I2C_ACK_ENABLE);

    i2c_ackpos_config(I2Cx, I2C_ACKPOS_CURRENT);

    return 0;
}

void resetI2cMaster(uint32_t I2Cx)
{
    i2c_software_reset_config(I2Cx, I2C_SRESET_SET);

    i2c_software_reset_config(I2Cx, I2C_SRESET_RESET);

    if(I2Cx == I2C1)
    {
        MASTER_I2C_Mode_Configu(0);
    }
    else
    {
        MASTER_I2C_Mode_Configu(1);
    }
}

/**
 * @brief 打印从机接收到的数据
 * @param 无
 * @retval 无
 */
void printIIC2Recv(void)
{
    printf("Slave Recv [%d]:", Rx_Idx_IIC);
    for (int i = 0; i < Rx_Idx_IIC; ++i)
    {
        printf("%02X ", Buffer_Rx_IIC[i]);
    }
    printf("\r\n");
}
